<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WebSocket-TCP Proxy Client</title>
  <style>
    body {
      font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      margin: 0;
      padding: 0;
      background: linear-gradient(120deg, #f3f4f6, #e5e7eb);
    }
    #container {
      width: 90%;
      margin: 20px auto;
      max-width: 800px;
      background: #ffffff;
      border-radius: 12px;
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      padding: 20px;
    }
    #messages {
      height: 300px;
      overflow-y: auto;
      background: #f9fafb;
      border: 1px solid #e5e7eb;
      padding: 10px;
      margin-bottom: 20px;
      border-radius: 8px;
      display: flex;
      flex-direction: column;
    }
    .message {
      margin-bottom: 10px;
      padding: 10px;
      border-radius: 8px;
      font-size: 14px;
      position: relative;
      display: flex;
      align-items: center;
      gap: 10px;
      max-width: 80%;
    }
    .message .avatar {
      width: 40px;
      height: 40px;
      background-color: #ddd;
      border-radius: 50%;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 12px;
      color: #333;
    }
    .message.me {
      background-color: #d1ecf1;
      text-align: left;
      align-self: flex-end;
    }
    .message.system {
      background-color: #ffddcc;
      font-size: 12px;
      padding: 6px;
      align-self: center;
      color: #6c757d;
      display: flex;
      justify-content: space-between;
    }
    .message.received {
      background-color: #ffffff;
      text-align: left;
      align-self: flex-start;
      border: 1px solid #e5e7eb;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
    }
    .timestamp {
      font-size: 10px;
      color: #6c757d;
      margin-left: auto;
    }
    #input-container {
      display: flex;
      gap: 10px;
      margin-bottom: 10px;
    }
    #input-container input,
    #input-container button {
      padding: 10px;
      font-size: 16px;
      border: 1px solid #ddd;
      border-radius: 4px;
    }
    #input-container input {
      flex: 1;
    }
    #input-container button {
      background-color: #007bff;
      color: white;
      cursor: pointer;
      transition: background-color 0.3s;
    }
    #input-container button:hover {
      background-color: #0056b3;
    }
    .button-group {
      display: flex;
      justify-content: space-between;
    }
    .connection-status {
      font-size: 12px;
      color: #6c757d;
      text-align: center;
      margin-bottom: 10px;
      display: flex;
      justify-content: space-between;
    }
    .connection-status .user-info {
      font-weight: bold;
      color: #28a745;
    }
  </style>
</head>
<body>
<div id="container">
  <h1 style="text-align: center; color: #333;">WebSocket-TCP Proxy Client</h1>
  <div id="messages"></div>
  <div class="connection-status">
    <span>状态: <span id="status-text">连接已关闭</span></span>
    <span class="user-info" id="user-info"></span>
  </div>
  <div id="input-container">
    <input type="number" id="receiver-id" placeholder="请输入接收方ID">
    <input type="text" id="message" placeholder="请输入消息内容">
    <button id="send">发送</button>
  </div>
</div>

<script>
  const serverUrl = "ws://127.0.0.1:8080"; // WebSocket 代理服务器地址
  const ws = new WebSocket(serverUrl);

  let userId = null;
  let heartbeatInterval = null;

  const MESSAGE_TYPES = {
    LOGIN: 0,
    HEART_BEAT: 1,
    SEND_MESSAGE: 3,
  };

  ws.onopen = () => {
    console.log("Connected to WebSocket server");
    updateConnectionStatus("已连接", "#28a745");

    userId = prompt("请输入您的用户ID:");
    if (userId) {
      sendJsonMessage({
        sender_id: parseInt(userId),
        receiver_id: null,
        message_type: MESSAGE_TYPES.LOGIN,
        context: "login request"
      });
      document.getElementById("user-info").textContent = `用户ID: ${userId}`;
      startHeartbeat();
    }
  };

  ws.onmessage = (event) => {
    try {
      const data = JSON.parse(event.data);
      console.log("Received:", data);

      const currentTime = new Date().toLocaleString();

      if (data.header && data.body && data.body.data === "心跳响应成功") {
        return; // 不展示心跳响应
      } else if (data.header && data.body && data.body.data) {
        const senderId = data.header.uid;
        const messageContent = data.body.data;
        displayMessage(messageContent, "received", currentTime, senderId);
      } else if (data.message_type === MESSAGE_TYPES.LOGIN) {
        displaySystemMessage("登录连接成功", currentTime);
      } else {
        displayMessage("收到未知消息", "server", currentTime);
      }
    } catch (error) {
      console.error("Error processing received message:", error);
      displayMessage("消息解析失败: " + error.message, "system");
    }
  };

  ws.onerror = (error) => {
    console.error("WebSocket error:", error);
    updateConnectionStatus("连接错误", "#dc3545");
    displayMessage("连接错误", "system");
  };

  ws.onclose = () => {
    console.log("WebSocket connection closed");
    updateConnectionStatus("连接已关闭", "#6c757d");
    displayMessage("连接已关闭", "system");
    stopHeartbeat();
  };

  document.getElementById("send").addEventListener("click", () => {
    const messageInput = document.getElementById("message");
    const receiverIdInput = document.getElementById("receiver-id");
    const messageText = messageInput.value.trim();
    const receiverId = receiverIdInput.value.trim();

    if (messageText && receiverId && ws.readyState === WebSocket.OPEN) {
      const message = {
        sender_id: parseInt(userId),
        receiver_id: parseInt(receiverId),
        message_type: MESSAGE_TYPES.SEND_MESSAGE,
        context: messageText
      };
      sendJsonMessage(message);
      displayMessage(messageText, "me", new Date().toLocaleString());
      messageInput.value = "";
    } else {
      alert("请输入接收方ID和消息内容！");
    }
  });

  function startHeartbeat() {
    if (heartbeatInterval) return;
    heartbeatInterval = setInterval(() => {
      if (ws.readyState === WebSocket.OPEN) {
        sendJsonMessage({
          sender_id: parseInt(userId),
          receiver_id: null,
          message_type: MESSAGE_TYPES.HEART_BEAT,
          context: "heartbeat"
        });
      }
    }, 10000);
  }

  function stopHeartbeat() {
    if (heartbeatInterval) {
      clearInterval(heartbeatInterval);
      heartbeatInterval = null;
    }
  }

  function displaySystemMessage(text, timestamp) {
    const messagesDiv = document.getElementById("messages");
    const messageDiv = document.createElement("div");
    messageDiv.className = "message system";

    const avatarDiv = document.createElement("div");
    avatarDiv.className = "avatar";
    avatarDiv.textContent = "系统";
    avatarDiv.style.backgroundColor = "#ff6f61";
    avatarDiv.style.color = "white";

    const textDiv = document.createElement("div");
    textDiv.textContent = text;

    const timestampSpan = document.createElement("span");
    timestampSpan.className = "timestamp";
    timestampSpan.textContent = timestamp;

    messageDiv.appendChild(avatarDiv);
    messageDiv.appendChild(textDiv);
    messageDiv.appendChild(timestampSpan);

    messagesDiv.appendChild(messageDiv);
    messagesDiv.scrollTop = messagesDiv.scrollHeight;
  }

  function displayMessage(text, type, timestamp = null, senderId = null) {
    const messagesDiv = document.getElementById("messages");
    const messageDiv = document.createElement("div");
    messageDiv.className = `message ${type}`;

    if (type === "received" && senderId) {
      const avatarDiv = document.createElement("div");
      avatarDiv.className = "avatar";
      avatarDiv.textContent = senderId;
      avatarDiv.style.backgroundColor = "#a5d6a7";
      messageDiv.appendChild(avatarDiv);
    }

    const textDiv = document.createElement("div");
    textDiv.textContent = text;
    messageDiv.appendChild(textDiv);

    if (timestamp) {
      const timestampSpan = document.createElement("span");
      timestampSpan.className = "timestamp";
      timestampSpan.textContent = timestamp;
      messageDiv.appendChild(timestampSpan);
    }

    messagesDiv.appendChild(messageDiv);
    messagesDiv.scrollTop = messagesDiv.scrollHeight;
  }

  function sendJsonMessage(message) {
    if (ws.readyState !== WebSocket.OPEN) {
      console.error("WebSocket connection is not open");
      return;
    }
    ws.send(JSON.stringify(message));
  }

  function updateConnectionStatus(statusText, color) {
    const statusDiv = document.getElementById("status-text");
    statusDiv.textContent = statusText;
    statusDiv.style.color = color;
  }
</script>
</body>
</html>